package service

import (
	"fmt"
	"math"
	"strconv"
	"time"
	"zimuzu_cvn_web_api/config"
	"zimuzu_cvn_web_api/model"
	"zimuzu_cvn_web_api/pkg/drive/redis"
	. "zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"
	"zimuzu_cvn_web_api/service/cache"
)

var (
	usdtCharges = []float64{1, 1.5, 2}
)

//获取手续费
func GetUsdtCharges() []float64 {
	return usdtCharges
}

//获取账户余额
func GetUsdtAmountBalance(uid int64) (re model.UsdtBalance, err error) {
	userMobile, err := model.GetUserMobile(config.C.DB.DB, uid)
	if err != nil {
		err = errno.GetDataErr
		return re, err
	}
	usdtAmount, err := model.GetUsdtAmount(config.C.DB.DB, uid)
	if err != nil {
		err = errno.GetDataErr
		return re, err
	}
	re.Area = userMobile.Area
	re.Mobile = userMobile.Mobile
	re.Balance = Decimal(usdtAmount.Balance, COIN_DECIMAL_USDT)
	return re, nil
}

//转账
func UsdtTransfer(uid int64, author string, params model.TransferParam) (id int64, err error) {
	var (
		status      int
		charge      float64
		banCacheKey string
		post        = make(map[string]string)
	)
	if config.C.Keys.TransferKey != "AC3FF6E4E68B063D" {
		if params.Value > 10 {
			err = errno.ErrTransValue
			return 0, err
		}
	}
	//校验参数
	if params.Value <= 0 {
		err = errno.ParamsError
		return 0, err
	}
	//检查是否为站内钱包
	toUserWalletAddress, isIntraAddress, err := GetCheckAddress(params.To)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	if uid == toUserWalletAddress.Uid {
		err = errno.ErrTransToSelf
		return 0, err
	}
	if isIntraAddress {
		charge = 0
	} else {
		if params.Speed < 0 || params.Speed >= len(usdtCharges) {
			err = errno.ParamsError
			return 0, err
		}
		charge = usdtCharges[params.Speed]
		if charge <= 0 {
			err = errno.SystemErr
			return 0, err
		}
	}
	amount := Decimal(params.Value-charge, COIN_DECIMAL_USDT)
	if amount <= 0 {
		err = errno.ErrLessCharge
		return 0, err
	}
	//检查转账是否开放
	cvnTransferOn, err := model.GetGlobalVarValue(config.C.DB.DB, 16)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	if cvnTransferOn != "1" {
		err = errno.CloseTransferTip
		return 0, err
	}
	//检查账号是否在黑名单
	ok, err := model.IsBlackUser(config.C.DB.DB, uid)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	if ok {
		err = errno.BlackUser
		return 0, err
	}
	//检查账户是否被冻结
	userAmount, err := model.GetUserAmount(uid)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	if userAmount.Status == 0 {
		err = errno.PayPasswordFreeze
		return 0, err
	}
	//支付密码错误次数过多冻结
	banCacheKey = cache.GetPayPasswordBanKey(uid)
	if ok := redis.Exists(banCacheKey); ok {
		err = errno.PayPasswordFreeze
		return 0, err
	}
	//检查是否绑定手机号
	userMobile, err := model.GetUserMobile(config.C.DB.DB, uid)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	if userMobile.Area == 0 || userMobile.Mobile == "" {
		err = errno.NotBindMobile
		return 0, err
	}
	//检查是否免验证码
	smsCodeChecked, err := IsTransferSmsCodeChecked(uid, author)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	//检查验证码是否正确
	if !smsCodeChecked {
		if errValid := ValidateCode(userMobile.Mobile, SendCodeSceneTransfer, params.Code); errValid != nil {
			err = errValid
			return 0, err
		}
		//设置短信验证码已校验缓存
		CodeCheckedCacheKey := cache.GetTransferSmsCodeCheckedKey(uid, author)
		ok, err = redis.Set(CodeCheckedCacheKey, 1, 1800)
		if err != nil || !ok {
			err = errno.UpdateDataErr
			return 0, err
		}
	}
	//检查支付密码是否校验成功
	if ok = IsPayPasswordChecked(uid, params.U); !ok {
		err = errno.PayPasswordCheckExpire
		return 0, err
	}
	DeleteU(uid, params.U)
	//付款人地址
	from, err := GetWalletAddress(uid)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	notExamine, err := UsdtNotExamine(uid, amount)
	if err != nil {
		err = errno.GetDataErr
		return 0, err
	}
	//提交事务
	if isIntraAddress {
		if notExamine {
			status = model.DealStatusSuccess
		} else {
			status = model.DealStatusCheck
		}
		tx, err := config.C.DB.DB.Beginx()
		if err != nil {
			err = errno.UpdateDataErr
			return 0, err
		}
		//付款账户扣款，记录流水
		updateAmountData := UpdateUsdtAmountParams{
			Uid:    uid,
			Amount: -amount,
			Source: model.LogSourceUsdtInnerOut,
			From:   from,
			To:     params.To,
			Status: status,
		}
		id, err = UpdateUsdtAmountBalance(tx, updateAmountData)
		if err != nil {
			_ = tx.Rollback()
			return 0, err
		}
		if notExamine {
			//收款账户收款、记录流水
			updateInnerUserAmountData := UpdateUsdtAmountParams{
				Uid:         toUserWalletAddress.Uid,
				Amount:      amount,
				Source:      model.LogSourceUsdtInnerIn,
				RelateId:    strconv.FormatInt(id, 10),
				RelateTable: TableUsdtLog,
				From:        from,
				To:          params.To,
			}
			_, err = UpdateUsdtAmountBalance(tx, updateInnerUserAmountData)
			if err != nil {
				_ = tx.Rollback()
				return 0, err
			}
		} else {
			usdtExamine := model.UsdtExamine{
				Uid:   uid,
				LogId: id,
			}
			err = model.AddUsdtExamine(tx, usdtExamine)
			if err != nil {
				_ = tx.Rollback()
				err = errno.UpdateDataErr
				return 0, err
			}
		}
		if err = tx.Commit(); err != nil {
			err = errno.UpdateDataErr
			return 0, err
		}
		return id, nil
	} else {
		tx, err := config.C.DB.DB.Beginx()
		if err != nil {
			err = errno.UpdateDataErr
			return 0, err
		}
		//账户扣款，记录流水
		updateAmountData := UpdateUsdtAmountParams{
			Uid:    uid,
			Amount: -amount,
			Source: model.LogSourceUsdtOut,
			From:   from,
			To:     params.To,
			Status: model.DealStatusCheck,
		}
		id, err = UpdateUsdtAmountBalance(tx, updateAmountData)
		if err != nil {
			_ = tx.Rollback()
			return 0, err
		}
		//手续费扣款、记录流水
		chargeLogData := UpdateUsdtAmountParams{
			Uid:         uid,
			Amount:      -charge,
			Source:      model.LogSourceUsdtFee,
			RelateId:    strconv.FormatInt(id, 10),
			RelateTable: TableUsdtLog,
		}
		_, err = UpdateUsdtAmountBalance(tx, chargeLogData)
		if err != nil {
			_ = tx.Rollback()
			return 0, err
		}
		if !notExamine {
			usdtExamine := model.UsdtExamine{
				Uid:   uid,
				LogId: id,
			}
			err = model.AddUsdtExamine(tx, usdtExamine)
			if err != nil {
				_ = tx.Rollback()
				err = errno.UpdateDataErr
				return 0, err
			}
		}
		if err = tx.Commit(); err != nil {
			err = errno.UpdateDataErr
			return 0, err
		}
		if notExamine {
			post["amount"] = fmt.Sprintf("%.0f", amount*math.Pow(10, COIN_DECIMAL_USDT))
			post["coin"] = COIN_NAME_USDT
			post["address"] = params.To
			post["requestId"] = COIN_NAME_USDT + "_" + strconv.FormatInt(id, 10)
			_, _ = model.GatewayRequest("POST", ApiTransfer, post, nil)
		}
		return id, nil
	}
}

//检查是否免审核
func UsdtNotExamine(uid int64, amount float64) (bool, error) {
	nowTime := time.Now().Unix()
	amount = math.Abs(amount)
	//触发条件：单笔限额
	if amount > UsdtExamineSingleQuota {
		return false, nil
	}
	//触发条件：存在审核中记录
	ok, err := model.ExistUsdtExamine(config.C.DB.DB, uid)
	if err != nil {
		return false, err
	}
	if ok {
		return false, nil
	}
	//触发条件：新地址
	userWalletAddress, err := model.GetUserWalletAddress(uid)
	if err != nil {
		return false, err
	}
	if nowTime-userWalletAddress.CreateTime < TimeFormatWeek && amount > UsdtExamineNewQuota {
		return false, nil
	}
	//获取充值总金额
	rechargeSum, err := model.SumUsdtLogSource(config.C.DB.DB, uid, model.LogSourceUsdtIn, 0)
	if err != nil {
		return false, err
	}
	//触发条件：小额充值
	if rechargeSum < UsdtExamineSmallRecharge && amount > UsdtExamineSmallRechargeQuota {
		return false, nil
	}
	//触发条件：超过充值金额
	if rechargeSum < amount && amount > UsdtExamineExceedQuota {
		return false, nil
	}
	//触发条件：日限额
	daySum, err := model.SumUsdtLogSource(config.C.DB.DB, uid, model.LogSourceUsdtOut, 1)
	if err != nil {
		return false, err
	}
	daySum = math.Abs(daySum)
	if daySum+amount > UsdtExamineDayQuota {
		return false, nil
	}
	//触发条件：周限额
	weekSum, err := model.SumUsdtLogSource(config.C.DB.DB, uid, model.LogSourceUsdtOut, 7)
	if err != nil {
		return false, err
	}
	weekSum = math.Abs(weekSum)
	if weekSum+amount > UsdtExamineWeekQuota {
		return false, nil
	}
	//触发条件：月限额
	monthSum, err := model.SumUsdtLogSource(config.C.DB.DB, uid, model.LogSourceUsdtOut, 30)
	if err != nil {
		return false, err
	}
	monthSum = math.Abs(monthSum)
	if monthSum+amount > UsdtExamineMonthQuota {
		return false, nil
	}
	return true, nil
}
